﻿using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditorInternal;
using UnityEngine;

namespace CF.CFLog.Editor
{
    /// <summary>
    /// Log Redirect
    /// </summary>
    public static class LogRedirect
    {
        private static readonly Regex LogRegex = new Regex(@" \(at (.+)\:(\d+)\)\r?\n");

        [OnOpenAsset(0)]
        private static bool OnOpenAsset(int instanceId, int line)
        {
            var name = EditorUtility.InstanceIDToObject(instanceId).name;
            if (name == "Log")
            {
                var logMsg = GetSelectedStackTrace();
                // Not CF.Log 
                if (!logMsg.Contains("Assets/CF/CFLog/Log.cs"))
                {
                    return false;
                }

                var match = LogRegex.Match(logMsg);
                // Match failed
                if (!match.Success)
                {
                    return false;
                }

                // 匹配第二个位置字符
                match = match.NextMatch();
                if (!match.Success)
                {
                    return false;
                }

                // Substring(7)是为了去除多了的/Assets
                var fileName = Path.Combine(Application.dataPath, match.Groups[1].Value.Substring(7));
                InternalEditorUtility.OpenFileAtLineExternal(fileName, int.Parse(match.Groups[2].Value));
                return true;
            }

            return false;
        }

        /// <summary>
        /// Get selected stack trace
        /// </summary>
        /// <returns></returns>
        private static string GetSelectedStackTrace()
        {
            Assembly editorWindowAssembly = typeof(EditorWindow).Assembly;

            System.Type consoleWindowType = editorWindowAssembly.GetType("UnityEditor.ConsoleWindow");
            if (consoleWindowType == null)
            {
                return null;
            }

            FieldInfo consoleWindowFieldInfo =
                consoleWindowType.GetField("ms_ConsoleWindow", BindingFlags.Static | BindingFlags.NonPublic);
            if (consoleWindowFieldInfo == null)
            {
                return null;
            }

            EditorWindow consoleWindow = consoleWindowFieldInfo.GetValue(null) as EditorWindow;
            if (consoleWindow == null)
            {
                return null;
            }

            if (consoleWindow != EditorWindow.focusedWindow)
            {
                return null;
            }

            FieldInfo activeTextFieldInfo =
                consoleWindowType.GetField("m_ActiveText", BindingFlags.Instance | BindingFlags.NonPublic);
            if (activeTextFieldInfo == null)
            {
                return null;
            }

            return (string) activeTextFieldInfo.GetValue(consoleWindow);
        }
    }
}